﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using SuperGo.Silverlight.WebApp;
using System.Windows.Media;

namespace SuperGo.Silverlight {
	public partial class FriendsList : Canvas {
		bool _userChangedTextBox = true;
		string _lastTextboxValue = "";
		private IEnumerable<WsPlayer> _allFriends = null;
		Canvas _controlBase;

		public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register("IsEnabled", typeof(bool), typeof(FriendsList), null);

		public bool IsEnabled {
			get {
				return (bool)this.GetValue(IsEnabledProperty);
			} 
			set {
				this.SetValue(IsEnabledProperty, value);
			}
		}

		public Brush Foreground {
			get {
				if (IsEnabled)
					return new SolidColorBrush(Colors.Black);
				else
					return new SolidColorBrush(Colors.Gray);
			}
		}

		public bool ReadOnly {
			get { return !IsEnabled; }
		}

		public IEnumerable<WsPlayer> AllFriends {
			get { return _allFriends; }
			set { _allFriends = value; }
		}

		public FriendsList() {
			InitializeComponent();

			_controlBase = (Canvas)_stackPanel.Parent;

			this.Loaded += new RoutedEventHandler(FriendsList_Loaded);
			this.SizeChanged += new SizeChangedEventHandler(FriendsList_SizeChanged);
		}

		void FriendsList_SizeChanged(object sender, SizeChangedEventArgs e) {
			Resize();
		}

		private void Resize() {
			FrameworkElement parentControl = _controlBase.Parent as FrameworkElement;
			double width = parentControl.ActualWidth;
			Resize(width);
		}

		private void Resize(double width) {
			this.Width = width;
			_stackPanel.Width = width;
		}

		public WsPlayer GetSelectedItem() {
			return AllFriends.SingleOrDefault(p => p.Name == FriendTextBox.Text);
		}

		public void SetSelectedItem(WsPlayer wsPlayer) {
			if (wsPlayer == null)
				FriendTextBox.Text = "";
			else
				FriendTextBox.Text = wsPlayer.Name;
			
			// setting the text box will result in a textchanged event, so set _userChangedTextBox to disable that event
			_userChangedTextBox = false;
			
			FriendsListBox.Visibility = Visibility.Collapsed;
		}

		void FriendsList_Loaded(object sender, RoutedEventArgs e) {
			FriendTextBox.TextChanged += new TextChangedEventHandler(FriendTextBox_TextChanged);
			Dropdown.Click += new RoutedEventHandler(Dropdown_Click);
			FriendsListBox.SelectionChanged += new SelectionChangedEventHandler(FriendsListBox_SelectionChanged);
			FriendsListBox.MouseLeftButtonUp += new MouseButtonEventHandler(FriendsListBox_MouseLeftButtonUp);

			IsFriendsListTextBoxVisible = false;
		}

		private bool IsFriendsListTextBoxVisible {
			get {
				return FriendsListBox.Visibility == Visibility.Visible;
			} 
			
			set {
				if (value) {
					FriendsListBox.Visibility = Visibility.Visible;
					_controlBase.SetValue(Canvas.ZIndexProperty, 1);
				} else {
					FriendsListBox.Visibility = Visibility.Collapsed;
					_controlBase.SetValue(Canvas.ZIndexProperty, -1);
				}
			}
		}
		
		void FriendsListBox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
			if (WasListItemClicked(e))
				IsFriendsListTextBoxVisible = false;
		}

		/// <summary>
		/// This is really hacky, but it's the best way I can figure out how to determine
		/// if some part of the scroll bar was clicked or an actual list item was clicked.
		/// </summary>
		private bool WasListItemClicked(MouseButtonEventArgs e) {
			Grid source = e.Source as Grid;
			if (source != null)
				if (source.ColumnDefinitions.Count == 0)
					return true;
			if (e.Source is TextBlock)
				return true;
			return false;
		}

		void FriendsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
			// ignore selection changed event if it list box is not visible or there is no selected item
			if (!IsFriendsListTextBoxVisible || FriendsListBox.SelectedItem == null)
				return;

			WsPlayer selectedItem = (WsPlayer)FriendsListBox.SelectedItem;
			if (selectedItem.Name != FriendTextBox.Text) {
				FriendTextBox.Text = selectedItem.Name;
				// setting the text box will result in a textchanged event, so set _userChangedTextBox to disable that event
				_userChangedTextBox = false;
			}
		}

		void Dropdown_Click(object sender, RoutedEventArgs e) {
			if (!IsEnabled)
				return;
			
			IsFriendsListTextBoxVisible = !IsFriendsListTextBoxVisible;
			FriendsListBox.ItemsSource = _allFriends;
		}

		void FriendTextBox_TextChanged(object sender, TextChangedEventArgs e) {
			// if this code triggered this event then don't do anything
			if (!_userChangedTextBox) {
				_userChangedTextBox = true;
				return;
			}

			string currentTextBoxValue = FriendTextBox.Text;

			bool userTypedACharacter = currentTextBoxValue.Length == _lastTextboxValue.Length + 1;
			_lastTextboxValue = currentTextBoxValue;

			bool textIsNothing = String.IsNullOrEmpty(currentTextBoxValue);
			bool filterReturnsNothing = false;

			if (!textIsNothing) {
				WsPlayer[] filteredFriends = _allFriends.Where(f => f.Name.ToLower().StartsWith(currentTextBoxValue.ToLower())).ToArray();
				FriendsListBox.ItemsSource = filteredFriends;

				filterReturnsNothing = filteredFriends.Length == 0;
				if (!filterReturnsNothing && userTypedACharacter) {
					string firstFriend = filteredFriends[0].Name;
					FriendTextBox.Text = firstFriend;
					FriendTextBox.Select(currentTextBoxValue.Length, firstFriend.Length - currentTextBoxValue.Length);

					// if we actually changed the value of the textbox, then we will fir TextChanged which we need to ignore
					if (firstFriend != currentTextBoxValue)
						_userChangedTextBox = false;
				}
			}

			// hide the friends list of the text is nothing or the filter doesn't return anything
			IsFriendsListTextBoxVisible = !(textIsNothing || filterReturnsNothing);
		}
	}
}
